from typing import Sequence

from app.crud.base_crud import BaseCRUD
from app.models.api import Api
from app.schemas.api_schema import ApiCreate, ApiUpdate
from app.schemas.query_schema import BaseQueryIn
from app.utils.file import load_file_data
from app.utils.list_extension import flatten_tree


class ApiCRUD(BaseCRUD[Api, ApiCreate, ApiUpdate]):
    async def get_all(self,query_in: BaseQueryIn = None) -> Sequence[Api]:
        """
        获取所有启用的
        :param query_in: 自定义查询
        :return: 已启用的列表
        """
        results = (await self.context.dynamic_query(query_in)
                   .include(self.model.children, criteria=(self.model, self.model.is_delete == False),recursion_depth=2)
                   .to_list())

        # 获取结果中所有ID（不包含children属性中的）
        result_ids = {item.id for item in results}

        # 使用了预先加载，children同时存在于顶层和子级
        # 没有parent_id值，说明为顶级
        # 父级id不在当前result_ids中，也要放置于顶层，用于table动态搜索
        top_level = [
            item
            for item in results
            if item.parent_id is None or item.parent_id not in result_ids
        ]

        return top_level

    async def sync(self):
        try:
            data = load_file_data("init_data/api.json")
            flat_data = await flatten_tree(data, is_del_children=True)
        except FileNotFoundError:
            raise
        db_objs = await self.context.to_list()
        name_path_dict = {item.name + item.path: item for item in db_objs}
        db_apis = []
        update_db_api_ids = []
        for item in flat_data:
            item_name_path = item["name"] + item["path"]
            if item_name_path in name_path_dict:
                db_obj = name_path_dict[item_name_path]
                update_api = ApiUpdate(**item, id=db_obj.id)
                update_data = update_api.model_dump(exclude_unset=True)
                db_obj.sqlmodel_update(update_data)
                db_obj.is_delete = False
                db_apis.append(db_obj)
                update_db_api_ids.append(db_obj.id)
            else:
                parent_name_path = item["tag"] + item["tag"]
                parent = name_path_dict[parent_name_path]
                parent_id = parent.id if parent is not None else None
                new_api = ApiCreate(**item, parent_id=parent_id)
                db_obj = self.model.model_validate(new_api)
                db_apis.append(db_obj)

        for item in db_objs:
            if item.id not in update_db_api_ids:
                item.is_delete = True
                db_apis.append(item)

        await self.context.add_all(entities=db_apis)

        return True

